﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Schema;
using OpenComposite.EII.Repository;
using OpenComposite.Mapper;

namespace OpenComposite.Repository.Designer
{
	public static class Mapping
	{
		public static void DoSubscriptionMapping(
			NamedBusinessObjectCollection subscribedBObjects,
			LogicalActivity targetLogAct,
			BusinessObject targetBObject)
		{
			List<XmlSchema> schemas = new List<XmlSchema>();
			List<XmlSchemaComplexType> types = new List<XmlSchemaComplexType>();
			foreach ( NamedBusinessObject item in subscribedBObjects ) {
				XmlSchema schema = item.BusinessObject.Schema;
				if ( schema.Items.Count != 0 ) {
					XmlSchemaElement elem = schema.Items[0] as XmlSchemaElement;
					if ( elem != null ) elem.Name = item.Name;
				}
				schemas.Add(schema);
			}

			XmlSchema xsdSubscriptions = createCompoundDocument(schemas);

			FormMapping frm = new FormMapping();

			frm.InitializeMapper(
				xsdSubscriptions,
				targetBObject.Schema,
				targetLogAct.InputXslt == null ? null : targetLogAct.InputXslt.InnerXml,
				targetLogAct.InputConnections,
				targetLogAct.ExtendedProperties.InputCodeMapping);

			if ( frm.ShowDialog() == DialogResult.OK ) {
				string map;
				XsltDocument xslt = frm.GetMapping(out map);
				if ( xslt != null && xslt.DocumentElement != null ) {
					targetLogAct.InputConnections = map;
					targetLogAct.InputXslt = xslt;
					targetLogAct.Save();
				}
			}
		}
		private static XmlSchema createCompoundDocument(List<XmlSchema> schemas)
		{
			if ( schemas.Count == 0 ) return null; // EXIT

			XmlSchemaSet xset = null;

			//init Compound Schema
			XmlSchema compSchema = new XmlSchema();
			compSchema.ElementFormDefault = XmlSchemaForm.Qualified;
			compSchema.AttributeFormDefault = XmlSchemaForm.Qualified;
			compSchema.TargetNamespace = schemas[0].TargetNamespace;
			compSchema.Namespaces.Add("tns", "http://www.OpenComposite.com/canonical_document");
			compSchema.Namespaces.Add("xsd", "http://www.w3.org/2001/XMLSchema");

			//init choice-Element for adding Elements to the Schema
			XmlSchemaElement element = new XmlSchemaElement();
			element.Name = "SubscribedDocuments";
			XmlSchemaComplexType complexType = new XmlSchemaComplexType();
			element.SchemaType = complexType;
			XmlSchemaSequence seq = new XmlSchemaSequence();
			complexType.Particle = seq;

			int counter = 0;
			foreach ( XmlSchema schema in schemas ) {
				xset = new XmlSchemaSet();
				foreach ( XmlQualifiedName qname in schema.Namespaces.ToArray() ) {
					if ( qname.Namespace == "http://www.w3.org/2001/XMLSchema" ||
						 qname.Namespace == "http://www.OpenComposite.com/canonical_document" )
						continue;

					compSchema.Namespaces.Add(string.Format("compSch{0}", counter),
						qname.Namespace);
					counter++;
				}
				xset.Add(schema);
				xset.Compile();
			}
			for ( int i = 0; i < schemas.Count; i++ ) {
				foreach ( XmlSchemaObject schemaObj in schemas[i].Items ) {
					bool exists = false;
					XmlSchemaElement xsElement = schemaObj as XmlSchemaElement;
					XmlSchemaType xsType = schemaObj as XmlSchemaType;
					if ( xsElement != null ) {
						foreach ( XmlSchemaObject xmlObj in seq.Items ) {
							XmlSchemaElement xsExistingElement = xmlObj as XmlSchemaElement;
							if ( xsExistingElement != null ) {
								if ( xsElement.QualifiedName == xsExistingElement.QualifiedName ) {
									exists = true;
									break;
								}
							}
						}
						if ( !exists ) seq.Items.Add(schemaObj);
					} else if ( xsType != null ) {
						foreach ( XmlSchemaObject xmlObj in compSchema.Items ) {
							XmlSchemaType xsExistingType = xmlObj as XmlSchemaType;
							if ( xsExistingType != null ) {
								if ( xsType.QualifiedName == xsExistingType.QualifiedName ) {
									exists = true;
									break;
								}
							}
						}
						if ( !exists ) compSchema.Items.Add(schemaObj);
					} else {
						if ( !compSchema.Items.Contains(schemaObj) ) {
							compSchema.Items.Add(schemaObj);
						}
					}
				}
			}

			//add compound Element that contains the subscribed Elements
			if ( compSchema.Items.Contains(element) == false ) {
				compSchema.Items.Add(element);
			}

			xset = new XmlSchemaSet();
			xset.Add(compSchema);
			//xset.ValidationEventHandler += new ValidationEventHandler(this.validationEventHandler);
			xset.Compile();

			return compSchema;
		}
	}
}
